
import * as THREE from "three";
import { elapsedTime } from "../../core/constants";

const vertexShader = `

#include <common>
#include <logdepthbuf_pars_vertex>

varying vec2 vUv;

uniform float uTime;
uniform float uScale;

float calculateSurface(float x, float z) {
    float y = 0.0;
    y += (sin(x * 1.0 / uScale + uTime * 1.0) + sin(x * 2.3 / uScale + uTime * 1.5) + sin(x * 3.3 / uScale + uTime * 0.4)) / 3.0;
    y += (sin(z * 0.2 / uScale + uTime * 1.8) + sin(z * 1.8 / uScale + uTime * 1.8) + sin(z * 2.8 / uScale + uTime * 0.8)) / 3.0;
    return y;
}

void main() {
    vUv = uv;
    vec3 pos = position;

    pos.y += calculateSurface(pos.x, pos.z);

    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    
    #include <logdepthbuf_vertex>
}  
`;

const fragmentShader = `
#include <common>
#include <logdepthbuf_pars_fragment>
varying vec2 vUv;

uniform sampler2D uMap;
uniform float uTime;
uniform vec3 uColor;

void main() {
    #include <logdepthbuf_fragment>

    vec2 uv = vUv * 10.0 + vec2(uTime * -0.05);

    uv.y += 0.01 * (sin(uv.x * 3.5 + uTime * 0.35) + sin(uv.x * 4.8 + uTime * 1.05) + sin(uv.x * 7.3 + uTime * 0.45)) / 3.0;
    uv.x += 0.12 * (sin(uv.y * 4.0 + uTime * 0.5) + sin(uv.y * 6.8 + uTime * 0.75) + sin(uv.y * 11.3 + uTime * 0.2)) / 3.0;
    uv.y += 0.12 * (sin(uv.x * 4.2 + uTime * 0.64) + sin(uv.x * 6.3 + uTime * 1.65) + sin(uv.x * 8.2 + uTime * 0.45)) / 3.0;

    vec4 tex1 = texture2D(uMap, uv * 1.0);
    vec4 tex2 = texture2D(uMap, uv * 1.0 + vec2(0.2));

    vec3 blue = uColor;

    gl_FragColor = vec4(blue + vec3(tex1.a * 0.9 - tex2.a * 0.02), 1.0);
}
`;

const { sin, cos } = Math

export class OceanPlane extends THREE.Mesh {

    #_scale = { value: 5 }

    /**
     * @param {number} 控制海面起伏程度
     */
    get hScale() { return this.#_scale.value }

    set hScale(value) { this.#_scale.value = value }

    #fn_x = (x, t, s) => (sin(x * 1.0 / s + t * 1.0) + sin(x * 2.3 / s + t * 1.5) + sin(x * 3.3 / s + t * 0.4)) / 3.0

    #fn_z = (z, t, s) => (sin(z * 0.2 / s + t * 1.8) + sin(z * 1.8 / s + t * 1.8) + sin(z * 2.8 / s + t * 0.8)) / 3.0

    #dx = (x, t, s) => 1.0 / 3.0 * (cos(x / s + t) / s + cos(2.3 * x / s + 1.5 * t) * 2.3 / s + cos(3.3 * x / s + 0.4 * t) * 3.3 / s)

    #dz = (z, t, s) => 1.0 / 3.0 * (cos(0.2 * z / s + 1.8 * t) * 0.2 / s + cos(1.8 * z / s + 1.8 * t) * 1.8 / s + cos(2.8 * z / s + 0.8 * t) * 2.8 / s)

    /**
     * @param {Object} oceanPlaneParameters - 参数对象
     * @param {number} [oceanPlaneParameters.width=100] - 平面的宽度 默认 = `100`
     * @param {number} [oceanPlaneParameters.height=100] - 平面的高度 默认 = `100`
     * @param {number} [oceanPlaneParameters.widthSegments=100] - 平面宽度的分段数 默认 = `100`
     * @param {number} [oceanPlaneParameters.heightSegments=100] - 平面高度的分段数 默认 = `100`
     * @param {THREE.Color} [oceanPlaneParameters.color=new THREE.Color('#0051da')] - 平面的颜色 默认 = `new THREE.Color('#0051da')`
     * @param {THREE.Texture} - 平面的纹理 
     */
    constructor(oceanPlaneParameters = {}) {

        super()

        const width = oceanPlaneParameters.width === undefined ? 100 : oceanPlaneParameters.width
        const height = oceanPlaneParameters.height === undefined ? 100 : oceanPlaneParameters.height
        const widthSegments = oceanPlaneParameters.widthSegments === undefined ? 100 : oceanPlaneParameters.widthSegments
        const heightSegments = oceanPlaneParameters.heightSegments === undefined ? 100 : oceanPlaneParameters.heightSegments

        const color = oceanPlaneParameters.color === undefined ? new THREE.Color('#0051da') : oceanPlaneParameters.color
        const texture = oceanPlaneParameters.texture

        this.#createGeometry(width, height, widthSegments, heightSegments)

        this.#createMatrrial(texture, color)

    }

    /**
     * 
     * @param {number} width 
     * @param {number} height 
     * @param {number} widthSegments 
     * @param {number} heightSegments 
     */
    #createGeometry(width, height, widthSegments, heightSegments) {

        this.geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments);

        this.geometry.rotateX(-Math.PI / 2);

    }

    #createMatrrial(texture, color) {

        if (texture !== undefined) {

            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

        }

        const uniforms = {
            uMap: { value: texture },
            uTime: elapsedTime,
            uColor: { value: color },
            uScale: this.#_scale,
            depthTest: true,
            depthWrite: true,
        };



        this.material = new THREE.ShaderMaterial({
            uniforms,
            vertexShader: vertexShader,
            fragmentShader: fragmentShader,
        });

    }

    getCurrentY(x, z) {

        const elapsedValue = elapsedTime.value

        let y = this.#fn_x(x, elapsedValue, this.#_scale.value);

        y += this.#fn_z(z, elapsedValue, this.#_scale.value);

        return y;

    }

    getKX(x) {

        return this.#dx(x, elapsedTime.value, this.#_scale.value)

    }

    getKZ(z) {

        return this.#dz(z, elapsedTime.value, this.#_scale.value)

    }

    getNormalAtPosition(x, z) {

        // 求出 斜率kx 和斜率kz
        const kx = this.getKX(x)
        const kz = this.getKZ(z)

        // 根据kx 和 kz 写出面法线
        return new THREE.Vector3(-kx, 1, -kz).normalize();

    }

}
